from abc import ABC, abstractmethod
from typing import Any, Dict

from app.core.constants import ExecutionStatus
from app.core.task.store.redis import RedisStore
from app.schemas.job import SchedulerJob, RedisJobExecutionResult
from app.utils.timezone import now


class BaseExecutor(ABC):
    def __init__(self, store: RedisStore):
        self.store = store
        self._task_results: Dict[str, RedisJobExecutionResult] = {}

    def _create_execution_result(self, job_id: str) -> RedisJobExecutionResult:
        start_time = now()
        return RedisJobExecutionResult(job_id=job_id, start_time=start_time, end_time=start_time, duration=0.0)

    def _update_execution_result(
        self, result: RedisJobExecutionResult, status: ExecutionStatus, execution_result: Any = None, error: Exception = None
    ) -> RedisJobExecutionResult:
        result.end_time = now()
        result.status = status
        result.duration = max(0.001, (result.end_time - result.start_time).total_seconds())

        if execution_result is not None:
            result.result = execution_result

        if error is not None:
            if status != ExecutionStatus.TIMEOUT and status != ExecutionStatus.CANCELLED:
                result.status = ExecutionStatus.FAILED
            result.error_message = (
                str(error)
                if str(error)
                else (
                    f"TimeoutError: 任务执行超时 (>{result.duration:.1f}秒)"
                    if status == ExecutionStatus.TIMEOUT
                    else "任务被取消" if status == ExecutionStatus.CANCELLED else "未知错误"
                )
            )

        return result

    @abstractmethod
    async def cancel_job(self, job_id: str) -> bool:
        pass

    @abstractmethod
    async def execute_job(self, job: SchedulerJob) -> RedisJobExecutionResult:
        pass
